package com.gjs.cd.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gjs.cd.manager.IpUtil;
import com.gjs.cd.manager.TableNameConvert;
import com.gjs.cd.pojo.dto.ActivationRecordDTO;
import com.gjs.cd.pojo.dto.CdCodeActivationRecordAll;
import com.gjs.cd.pojo.dto.CdCodeCheckReq;
import com.gjs.cd.pojo.dto.CodeCheckReq;
import com.gjs.cd.pojo.entity.*;
import com.gjs.cd.service.*;
import com.gjs.common.enums.entity.StatusEnum;
import com.gjs.common.manager.SecurityOauthUtil;
import com.gjs.common.manager.response.RspBody;
import com.gjs.common.microservice.api.IResourceMicroService;
import com.gjs.common.pojo.dto.resource.ResourceDTO;
import com.gjs.common.pojo.dto.resource.ResourceQueryDTO;
import com.gjs.common.pojo.dto.user.UserInfoDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhongwenguang
 * @date 2022-3-28 9:19
 */
@RestController
@Slf4j
@Api(tags = "激活码激活，光盘程序调用")
@RequestMapping("/gp")
@RequiredArgsConstructor
public class CdCodeCkeckController {

    private final ICodeService iCodeService;
    private final ICdCodeGenerateBatchService iCdCodeGenerateBatchService;
    private final ICdCodeActivationRecord iCdCodeActivationRecord;
    private final ICdDetailService iCdDetailService;
    private final ICdResourceService iCdResourceService;
    @DubboReference
    private IResourceMicroService iResourceMicroService;
    @Autowired
    private ICdDetailService cdDetailService;

    @Autowired
    private ICdCodeValidTermService cdCodeValidTermService;

    @Autowired
    private SecurityOauthUtil securityOauthUtil;

    @Autowired
    private ICommonService iCommonService;

    //获取激活码可以激活的次数
    @Value("${cd.onceCodeCanUseNum}")
    private Integer onceCodeCanUseNum;

    @GetMapping("/check")
    @ApiOperation("激活码验证")
    public RspBody<CodeCheckReq> check(HttpServletRequest request, CdCodeCheckReq cdCodeCheckReq){

        /**
         * 判断激活码是否有效，有效则增加激活记录并返回对应的压缩包链接
         * 判断的基本流程为：
         * 1.判断激活码、硬件地址是否为空，为空不处理直接返回错误；
         * 2.通过accessToken获取用户的userSn，并判断userSn是否为空，为空不处理直接返回错误；
         * 3.根据激活码组装表名，激活码表和激活记录表
         * 4.判断激活码是否存在
         * 5.判断该激活码和该硬件地址是否已经激活过，如果已经激活过不增加激活次数，直接返回数据，否则需要增加一条激活记录
         */
        //获取IP地址
        String ipAddress = IpUtil.getIpAddr(request);
        //判断激活码是否为空
        CodeCheckReq codeCheckReq = new CodeCheckReq();
        String activationCode = cdCodeCheckReq.getActivationCode();//获取激活码
        if (null == activationCode || StringUtils.isBlank(activationCode)){
            return RspBody.error("激活码不能为空！");
        }
        //判断硬件信息是否为空
        String deviceMac = cdCodeCheckReq.getDeviceMac();//获取硬件地址
        if (null == deviceMac || StringUtils.isBlank(deviceMac)){
            return RspBody.error("硬件地址为空！");
        }
        //判断该用户userSn是否为空
        String userSn = securityOauthUtil.getUserSnByJwt();//获取userSn
        if (null == userSn || StringUtils.isBlank(userSn)){
            return RspBody.error("用户信息错误！");
        }

        String tableNameSuffix = activationCode.substring(0,4).toLowerCase();//获取激活码前四位并转为小写
        Code code = iCodeService.queryByCode("cd_code_"+tableNameSuffix,activationCode);//查询激活码表
        if (code == null){
            //激活码不存在，说明激活码错误
            return RspBody.error("激活码错误！");
        }else{
            //激活码存在，检查激活次数
            Long activationCodeId = code.getId();//获取该激活码对应的id
            String recordTableName = "cd_code_activation_record_"+tableNameSuffix;//拼接生成激活码激活记录表名
            List<CdCodeActivationRecord> list = iCdCodeActivationRecord.codeCheckRecord(recordTableName,activationCodeId);//获取该激活码的激活记录
            Integer recordNum = list.size();
            if (recordNum>=onceCodeCanUseNum){
                return RspBody.error("激活次数已经超过"+onceCodeCanUseNum+"次！");
            }

            //查询激活码记录表,通过激活码id、userSn和deviceMac查询
            CdCodeActivationRecord r = new CdCodeActivationRecord();
            r.setUserSn(userSn);
            r.setDeviceMac(deviceMac);
            r.setActivationCodeId(activationCodeId);
            CdCodeActivationRecord record = iCdCodeActivationRecord.checkRecord(recordTableName,r);//查询激活记录

            if (record == null){
                //record为null说明该激活码、该userSn和该deviceMac没有被激活过，此时需要增加一条激活记录，否则不用
                CdCodeActivationRecord cdCodeActivationRecord = new CdCodeActivationRecord();
                cdCodeActivationRecord.setActivationCodeId(activationCodeId);
                cdCodeActivationRecord.setDeviceIp(ipAddress);
                cdCodeActivationRecord.setDeviceMac(deviceMac);
                cdCodeActivationRecord.setUserSn(userSn);
                iCdCodeActivationRecord.addRecord(recordTableName,cdCodeActivationRecord);
            }
            //以下是组装返回结果
            Long bacthId = code.getBatchId();//获取激活码id
            //通过bacthId获取CdCodeGenerateBatch
            CdCodeGenerateBatch cdCodeGenerateBatch = iCdCodeGenerateBatchService.getOne(new LambdaQueryWrapper<CdCodeGenerateBatch>().eq(CdCodeGenerateBatch::getId, bacthId));
            //获取光盘品种cdId
            Long cdId = cdCodeGenerateBatch.getCdId();
            //通过cdId获取cd的详情
            CdDetail cdDetail = cdDetailService.detail(cdId);
            //设置光盘中文名称
            codeCheckReq.setCdName(cdDetail.getCdName());
            //设置光盘英文名称
            codeCheckReq.setCdNameEn(cdDetail.getCdNameEn());
            //获取过期时间
            Long validTermId = cdCodeGenerateBatch.getValidTermId();//获取过期时间id
            LocalDateTime expireTime = cdCodeValidTermService.getById(validTermId).getExpireTime();
            //设置过期时间
            codeCheckReq.setExpireTime(expireTime);
            //通过光盘id获取光盘资源
            List<CdResource> cdResourceList = iCdResourceService.list(new LambdaQueryWrapper<CdResource>().eq(CdResource::getCdId,cdId).eq(CdResource::getStatus, StatusEnum.ENABLE));
            List<Long> ids = new ArrayList<>();
            for (int i=0;i<cdResourceList.size();i++){
                ids.add(cdResourceList.get(i).getResourceId());
            }
            ResourceQueryDTO resourceQueryDTO = new ResourceQueryDTO();
            resourceQueryDTO.setIds(ids);
            List<ResourceDTO> resourceDTOList = iResourceMicroService.listResources(resourceQueryDTO);
            codeCheckReq.setResourceDTOList(resourceDTOList);
            return RspBody.success(codeCheckReq);
        }
    }

    //根据用户id获取激活记录
    @ApiOperation("根据用户id获取激活记录")
    @GetMapping("/get_record")
    public RspBody<List<ActivationRecordDTO>> getRecord(){
        List<ActivationRecordDTO> result = new ArrayList<>();
        //判断该用户userSn是否为空
        String userSn = securityOauthUtil.getUserSnByJwt();//获取userSn
        if (null == userSn || StringUtils.isBlank(userSn)){
            return RspBody.error("用户信息错误！");
        }
        //获取所有的激活记录表名称
        List<String> tableNameList = iCommonService.queryRecordTableName();
        //逐个查询激活记录表
//        List<Map<String,Object>> list = new ArrayList<>();//所有激活记录
//        for (int i=0;i<tableNameList.size();i++){
//            String tableName = tableNameList.get(i);//获取激活码表表名
//            List<Long> ids = iCdCodeActivationRecord.queryUserRecord(tableName,userSn);//获取用户在当前表的所有激活记录
//
//        }

        for (int i=0;i<tableNameList.size();i++){
            String tableName = tableNameList.get(i);//获取激活码记录表表名
            List<Long> activationCodeIds = iCdCodeActivationRecord.queryUserRecord(tableName,userSn);//获取所有的激活码id
            List<Code> codeList = iCodeService.queryCodeList(new TableNameConvert().toCodeTableName(tableName),activationCodeIds);
            for (int j=0;j<codeList.size();j++){
                ActivationRecordDTO activationRecordDTO = new ActivationRecordDTO();
                activationRecordDTO.setActivationCode(codeList.get(j).getActivationCode());//设置激活码

                Long batchId = codeList.get(j).getBatchId();//批次id
                //通过batchId获取批次实体
                CdCodeGenerateBatch cdCodeGenerateBatch = iCdCodeGenerateBatchService.getById(batchId);
                //通过批次实体获取cdId
                Long cdId = cdCodeGenerateBatch.getCdId();
                //通过批次实体获取validTermId
                Long validTermId = cdCodeGenerateBatch.getValidTermId();

                //通过cdId获取标题
                activationRecordDTO.setCdName(iCdDetailService.getById(cdId).getCdName());
                //通过validTermId获取过期日期
                activationRecordDTO.setExpireTime(cdCodeValidTermService.getById(validTermId).getExpireTime());

                result.add(activationRecordDTO);
            }
        }
        return RspBody.success(result);
    }

    //获取资源
    @ApiOperation("通过用户id、设备ip、设备Mac地址获取资源，主要应用情景为：同一个用户同一台电脑卸载电脑下载后还可以用")
    @GetMapping("/get")
    public RspBody<List<CodeCheckReq>> getResource(String deviceMac){
        /**
         * 流程：
         * 1.获取userSn
         * 2.获取所有的激活码记录表名称
         * 3.查询所有激活码记录表中的数据
         * 4.
         */
        List<CodeCheckReq> result = new ArrayList<>();
        String userSn = securityOauthUtil.getUserSnByJwt();//获取userSn
        //获取所有的激活码记录表名称
        List<String> tableNameList = iCommonService.queryRecordTableName();
        List<CdCodeActivationRecordAll> cdCodeActivationRecordAllArrayList = new ArrayList<>();
        for (int i=0;i<tableNameList.size();i++){
            CdCodeActivationRecordAll cdCodeActivationRecordAll = new CdCodeActivationRecordAll();
            cdCodeActivationRecordAll.setCdCodeActivationRecordList(iCdCodeActivationRecord.queryAllRecord(tableNameList.get(i),userSn,deviceMac));
            cdCodeActivationRecordAll.setTableName(tableNameList.get(i));
            cdCodeActivationRecordAllArrayList.add(cdCodeActivationRecordAll);
        }

        //开始组装返回结构
        for (int i=0;i<cdCodeActivationRecordAllArrayList.size();i++){
            //获取对应record的表名
            String tableName = cdCodeActivationRecordAllArrayList.get(i).getTableName();
            List<CdCodeActivationRecord> cdCodeActivationRecordList = cdCodeActivationRecordAllArrayList.get(i).getCdCodeActivationRecordList();
            for (int j=0;j<cdCodeActivationRecordList.size();j++){
                //根据record表获取activationCodeId（需要根据不同的表查询）
                //通过activationCodeId获取code实体
                //通过code实体获取批次表id，batch_id
                //通过batch_id获取批次实体
                //通过批次实体获取cd_id和valid_term_id
                //通过valid_term_id获取过期时间，在过期时间内查询以下数据
                //通过cd_id获取cd_details表实体,并获得相关数据
                //获取cd_details表中对应的资源
            }

        }


        return RspBody.success(result);
    }


}
